package org.jvm.instruction.base;

import org.jvm.instruction.comparisons.branch.ifacmp.*;
import org.jvm.instruction.comparisons.branch.ifcond.*;
import org.jvm.instruction.comparisons.branch.ificmp.*;
import org.jvm.instruction.comparisons.dcmp.*;
import org.jvm.instruction.comparisons.fcmp.*;
import org.jvm.instruction.comparisons.lcmp.LCMP;
import org.jvm.instruction.constants.*;
import org.jvm.instruction.control.*;
import org.jvm.instruction.control.ret.*;
import org.jvm.instruction.conversions.d2x.*;
import org.jvm.instruction.conversions.f2x.*;
import org.jvm.instruction.conversions.i2x.*;
import org.jvm.instruction.conversions.l2x.*;
import org.jvm.instruction.extended.*;
import org.jvm.instruction.loads.aload.*;
import org.jvm.instruction.loads.dload.*;
import org.jvm.instruction.loads.fload.*;
import org.jvm.instruction.loads.iload.*;
import org.jvm.instruction.loads.lload.*;
import org.jvm.instruction.math.IINC;
import org.jvm.instruction.math.add.*;
import org.jvm.instruction.math.and.*;
import org.jvm.instruction.math.div.*;
import org.jvm.instruction.math.mul.*;
import org.jvm.instruction.math.neg.*;
import org.jvm.instruction.math.or.*;
import org.jvm.instruction.math.rem.*;
import org.jvm.instruction.math.sh.*;
import org.jvm.instruction.math.sub.*;
import org.jvm.instruction.math.xor.*;
import org.jvm.instruction.references.*;
import org.jvm.instruction.references.array.ARRAY_LENGTH;
import org.jvm.instruction.references.array.aload.*;
import org.jvm.instruction.references.array.astore.*;
import org.jvm.instruction.references.array.newarray.*;
import org.jvm.instruction.references.invokemethod.*;
import org.jvm.instruction.stack.dup.*;
import org.jvm.instruction.stack.pop.*;
import org.jvm.instruction.stack.swap.SWAP;
import org.jvm.instruction.stores.astore.*;
import org.jvm.instruction.stores.dstore.*;
import org.jvm.instruction.stores.fstore.*;
import org.jvm.instruction.stores.istore.*;
import org.jvm.instruction.stores.lstore.*;


/**
 * 指令工厂
 *
 * @author 海燕
 * @date 2023/1/30
 */
public class InstructionFactory {

    /**
     * 无操作数的指令使用单例
     */
    private static final Instruction nop = new NOP();
    private static final Instruction aconst_null = new ACONST_NULL();
    private static final Instruction iconst_m1 = new ICONST_M1();
    private static final Instruction iconst_0 = new ICONST_0();
    private static final Instruction iconst_1 = new ICONST_1();
    private static final Instruction iconst_2 = new ICONST_2();
    private static final Instruction iconst_3 = new ICONST_3();
    private static final Instruction iconst_4 = new ICONST_4();
    private static final Instruction iconst_5 = new ICONST_5();
    private static final Instruction lconst_0 = new LCONST_0();
    private static final Instruction lconst_1 = new LCONST_1();
    private static final Instruction fconst_0 = new FCONST_0();
    private static final Instruction fconst_1 = new FCONST_1();
    private static final Instruction fconst_2 = new FCONST_2();
    private static final Instruction dconst_0 = new DCONST_0();
    private static final Instruction dconst_1 = new DCONST_1();
    private static final Instruction iload_0 = new ILOAD_0();
    private static final Instruction iload_1 = new ILOAD_1();
    private static final Instruction iload_2 = new ILOAD_2();
    private static final Instruction iload_3 = new ILOAD_3();
    private static final Instruction lload_0 = new LLOAD_0();
    private static final Instruction lload_1 = new LLOAD_1();
    private static final Instruction lload_2 = new LLOAD_2();
    private static final Instruction lload_3 = new LLOAD_3();
    private static final Instruction fload_0 = new FLOAD_0();
    private static final Instruction fload_1 = new FLOAD_1();
    private static final Instruction fload_2 = new FLOAD_2();
    private static final Instruction fload_3 = new FLOAD_3();
    private static final Instruction dload_0 = new DLOAD_0();
    private static final Instruction dload_1 = new DLOAD_1();
    private static final Instruction dload_2 = new DLOAD_2();
    private static final Instruction dload_3 = new DLOAD_3();
    private static final Instruction aload_0 = new ALOAD_0();
    private static final Instruction aload_1 = new ALOAD_1();
    private static final Instruction aload_2 = new ALOAD_2();
    private static final Instruction aload_3 = new ALOAD_3();
    private static final Instruction istore_0 = new ISTORE_0();
    private static final Instruction istore_1 = new ISTORE_1();
    private static final Instruction istore_2 = new ISTORE_2();
    private static final Instruction istore_3 = new ISTORE_3();
    private static final Instruction lstore_0 = new LSTORE_0();
    private static final Instruction lstore_1 = new LSTORE_1();
    private static final Instruction lstore_2 = new LSTORE_2();
    private static final Instruction lstore_3 = new LSTORE_3();
    private static final Instruction fstore_0 = new FSTORE_0();
    private static final Instruction fstore_1 = new FSTORE_1();
    private static final Instruction fstore_2 = new FSTORE_2();
    private static final Instruction fstore_3 = new FSTORE_3();
    private static final Instruction dstore_0 = new DSTORE_0();
    private static final Instruction dstore_1 = new DSTORE_1();
    private static final Instruction dstore_2 = new DSTORE_2();
    private static final Instruction dstore_3 = new DSTORE_3();
    private static final Instruction astore_0 = new ASTORE_0();
    private static final Instruction astore_1 = new ASTORE_1();
    private static final Instruction astore_2 = new ASTORE_2();
    private static final Instruction astore_3 = new ASTORE_3();
    private static final Instruction pop = new POP();
    private static final Instruction pop2 = new POP2();
    private static final Instruction dup = new DUP();
    private static final Instruction dup_x1 = new DUP_X1();
    private static final Instruction dup_x2 = new DUP_X2();
    private static final Instruction dup2 = new DUP2();
    private static final Instruction dup2_x1 = new DUP2_X1();
    private static final Instruction dup2_x2 = new DUP2_X2();
    private static final Instruction swap = new SWAP();
    private static final Instruction iadd = new IADD();
    private static final Instruction ladd = new LADD();
    private static final Instruction fadd = new FADD();
    private static final Instruction dadd = new DADD();
    private static final Instruction isub = new ISUB();
    private static final Instruction lsub = new LSUB();
    private static final Instruction fsub = new FSUB();
    private static final Instruction dsub = new DSUB();
    private static final Instruction imul = new IMUL();
    private static final Instruction lmul = new LMUL();
    private static final Instruction fmul = new FMUL();
    private static final Instruction dmul = new DMUL();
    private static final Instruction idiv = new IDIV();
    private static final Instruction ldiv = new LDIV();
    private static final Instruction fdiv = new FDIV();
    private static final Instruction ddiv = new DDIV();
    private static final Instruction irem = new IREM();
    private static final Instruction lrem = new LREM();
    private static final Instruction frem = new FREM();
    private static final Instruction drem = new DREM();
    private static final Instruction ineg = new INEG();
    private static final Instruction lneg = new LNEG();
    private static final Instruction fneg = new FNEG();
    private static final Instruction dneg = new DNEG();
    private static final Instruction ishl = new ISHL();
    private static final Instruction lshl = new LSHL();
    private static final Instruction ishr = new ISHR();
    private static final Instruction lshr = new LSHR();
    private static final Instruction iushr = new IUSHR();
    private static final Instruction lushr = new LUSHR();
    private static final Instruction iand = new IAND();
    private static final Instruction land = new LAND();
    private static final Instruction ior = new IOR();
    private static final Instruction lor = new LOR();
    private static final Instruction ixor = new IXOR();
    private static final Instruction lxor = new LXOR();
    private static final Instruction i2l = new I2L();
    private static final Instruction i2f = new I2F();
    private static final Instruction i2d = new I2D();
    private static final Instruction l2i = new L2I();
    private static final Instruction l2f = new L2F();
    private static final Instruction l2d = new L2D();
    private static final Instruction f2i = new F2I();
    private static final Instruction f2l = new F2L();
    private static final Instruction f2d = new F2D();
    private static final Instruction d2i = new D2I();
    private static final Instruction d2l = new D2L();
    private static final Instruction d2f = new D2F();
    private static final Instruction i2b = new I2B();
    private static final Instruction i2c = new I2C();
    private static final Instruction i2s = new I2S();
    private static final Instruction lcmp = new LCMP();
    private static final Instruction fcmpl = new FCMPL();
    private static final Instruction fcmpg = new FCMPG();
    private static final Instruction dcmpl = new DCMPL();
    private static final Instruction dcmpg = new DCMPG();
    private static final Instruction ireturn = new IRETURN();
    private static final Instruction lreturn = new LRETURN();
    private static final Instruction freturn = new FRETURN();
    private static final Instruction dreturn = new DRETURN();
    private static final Instruction areturn = new ARETURN();
    private static final Instruction _return = new RETURN();
    private static final Instruction invoke_native = new INVOKE_NATIVE();
    private static final Instruction athrow = new ATHROW();
    private static final Instruction arraylength = new ARRAY_LENGTH();
    private static final Instruction iaload = new IALOAD();
    private static final Instruction laload = new LALOAD();
    private static final Instruction faload = new FALOAD();
    private static final Instruction daload = new DALOAD();
    private static final Instruction aaload = new AALOAD();
    private static final Instruction baload = new BALOAD();
    private static final Instruction caload = new CALOAD();
    private static final Instruction saload = new SALOAD();
    private static final Instruction iastore = new IASTORE();
    private static final Instruction lastore = new LASTORE();
    private static final Instruction fastore = new FASTORE();
    private static final Instruction dastore = new DASTORE();
    private static final Instruction aastore = new AASTORE();
    private static final Instruction bastore = new BASTORE();
    private static final Instruction castore = new CASTORE();
    private static final Instruction sastore = new SASTORE();
    private static final Instruction monitorenter = new MONITOR_ENTER();
    private static final Instruction monitorexit = new MONITOR_EXIT();

    public static Instruction newInstruction(int opcode) {
        switch (opcode) {
            case 0x00:
                return nop;
            case 0x01:
                return aconst_null;
            case 0x02:
                return iconst_m1;
            case 0x03:
                return iconst_0;
            case 0x04:
                return iconst_1;
            case 0x05:
                return iconst_2;
            case 0x06:
                return iconst_3;
            case 0x07:
                return iconst_4;
            case 0x08:
                return iconst_5;
            case 0x09:
                return lconst_0;
            case 0x0a:
                return lconst_1;
            case 0x0b:
                return fconst_0;
            case 0x0c:
                return fconst_1;
            case 0x0d:
                return fconst_2;
            case 0x0e:
                return dconst_0;
            case 0x0f:
                return dconst_1;
            case 0x10:
                return new BIPUSH();
            case 0x11:
                return new SIPUSH();
            case 0x15:
                return new ILOAD();
            case 0x16:
                return new LLOAD();
            case 0x17:
                return new FLOAD();
            case 0x18:
                return new DLOAD();
            case 0x19:
                return new ALOAD();
            case 0x1a:
                return iload_0;
            case 0x1b:
                return iload_1;
            case 0x1c:
                return iload_2;
            case 0x1d:
                return iload_3;
            case 0x1e:
                return lload_0;
            case 0x1f:
                return lload_1;
            case 0x20:
                return lload_2;
            case 0x21:
                return lload_3;
            case 0x22:
                return fload_0;
            case 0x23:
                return fload_1;
            case 0x24:
                return fload_2;
            case 0x25:
                return fload_3;
            case 0x26:
                return dload_0;
            case 0x27:
                return dload_1;
            case 0x28:
                return dload_2;
            case 0x29:
                return dload_3;
            case 0x2a:
                return aload_0;
            case 0x2b:
                return aload_1;
            case 0x2c:
                return aload_2;
            case 0x2d:
                return aload_3;
            case 0x36:
                return new ISTORE();
            case 0x37:
                return new LSTORE();
            case 0x38:
                return new FSTORE();
            case 0x39:
                return new DSTORE();
            case 0x3a:
                return new ASTORE();
            case 0x3b:
                return istore_0;
            case 0x3c:
                return istore_1;
            case 0x3d:
                return istore_2;
            case 0x3e:
                return istore_3;
            case 0x3f:
                return lstore_0;
            case 0x40:
                return lstore_1;
            case 0x41:
                return lstore_2;
            case 0x42:
                return lstore_3;
            case 0x43:
                return fstore_0;
            case 0x44:
                return fstore_1;
            case 0x45:
                return fstore_2;
            case 0x46:
                return fstore_3;
            case 0x47:
                return dstore_0;
            case 0x48:
                return dstore_1;
            case 0x49:
                return dstore_2;
            case 0x4a:
                return dstore_3;
            case 0x4b:
                return astore_0;
            case 0x4c:
                return astore_1;
            case 0x4d:
                return astore_2;
            case 0x4e:
                return astore_3;
            case 0x57:
                return pop;
            case 0x58:
                return pop2;
            case 0x59:
                return dup;
            case 0x5a:
                return dup_x1;
            case 0x5b:
                return dup_x2;
            case 0x5c:
                return dup2;
            case 0x5d:
                return dup2_x1;
            case 0x5e:
                return dup2_x2;
            case 0x5f:
                return swap;
            case 0x60:
                return iadd;
            case 0x61:
                return ladd;
            case 0x62:
                return fadd;
            case 0x63:
                return dadd;
            case 0x64:
                return isub;
            case 0x65:
                return lsub;
            case 0x66:
                return fsub;
            case 0x67:
                return dsub;
            case 0x68:
                return imul;
            case 0x69:
                return lmul;
            case 0x6a:
                return fmul;
            case 0x6b:
                return dmul;
            case 0x6c:
                return idiv;
            case 0x6d:
                return ldiv;
            case 0x6e:
                return fdiv;
            case 0x6f:
                return ddiv;
            case 0x70:
                return irem;
            case 0x71:
                return lrem;
            case 0x72:
                return frem;
            case 0x73:
                return drem;
            case 0x74:
                return ineg;
            case 0x75:
                return lneg;
            case 0x76:
                return fneg;
            case 0x77:
                return dneg;
            case 0x78:
                return ishl;
            case 0x79:
                return lshl;
            case 0x7a:
                return ishr;
            case 0x7b:
                return lshr;
            case 0x7c:
                return iushr;
            case 0x7d:
                return lushr;
            case 0x7e:
                return iand;
            case 0x7f:
                return land;
            case 0x80:
                return ior;
            case 0x81:
                return lor;
            case 0x82:
                return ixor;
            case 0x83:
                return lxor;
            case 0x84:
                return new IINC();
            case 0x85:
                return i2l;
            case 0x86:
                return i2f;
            case 0x87:
                return i2d;
            case 0x88:
                return l2i;
            case 0x89:
                return l2f;
            case 0x8a:
                return l2d;
            case 0x8b:
                return f2i;
            case 0x8c:
                return f2l;
            case 0x8d:
                return f2d;
            case 0x8e:
                return d2i;
            case 0x8f:
                return d2l;
            case 0x90:
                return d2f;
            case 0x91:
                return i2b;
            case 0x92:
                return i2c;
            case 0x93:
                return i2s;
            case 0x94:
                return lcmp;
            case 0x95:
                return fcmpl;
            case 0x96:
                return fcmpg;
            case 0x97:
                return dcmpl;
            case 0x98:
                return dcmpg;
            case 0x99:
                return new IFEQ();
            case 0x9a:
                return new IFNE();
            case 0x9b:
                return new IFLT();
            case 0x9c:
                return new IFGE();
            case 0x9d:
                return new IFGT();
            case 0x9e:
                return new IFLE();
            case 0x9f:
                return new IF_ICMPEQ();
            case 0xa0:
                return new IF_ICMPNE();
            case 0xa1:
                return new IF_ICMPLT();
            case 0xa2:
                return new IF_ICMPGE();
            case 0xa3:
                return new IF_ICMPGT();
            case 0xa4:
                return new IF_ICMPLE();
            case 0xa5:
                return new IF_ACMPEQ();
            case 0xa6:
                return new IF_ACMPNE();
            case 0xa7:
                return new GOTO();
            case 0xaa:
                return new TABLE_SWITCH();
            case 0xab:
                return new LOOKUP_SWITCH();
            case 0xc4:
                return new WIDE();
            case 0xc6:
                return new IFNULL();
            case 0xc7:
                return new IFNONNULL();
            case 0xc8:
                return new GOTO_W();
            case 0xc0:
                return new CHECK_CAST();
            case 0xc1:
                return new INSTANCE_OF();
            case 0xb2:
                return new GET_STATIC();
            case 0xb3:
                return new PUT_STATIC();
            case 0xb4:
                return new GET_FIELD();
            case 0xb5:
                return new PUT_FIELD();
            case 0x12:
                return new LDC();
            case 0x13:
                return new LDC_W();
            case 0x14:
                return new LDC2_W();
            case 0xbb:
                return new NEW();
            case 0xb7:
                return new INVOKE_SPECIAL();
            case 0xb6:
                return new INVOKE_VIRTUAL();
            case 0xb8:
                return new INVOKE_STATIC();
            case 0xb9:
                return new INVOKE_INTERFACE();
            case 0xac:
                return ireturn;
            case 0xad:
                return lreturn;
            case 0xae:
                return freturn;
            case 0xaf:
                return dreturn;
            case 0xb0:
                return areturn;
            case 0xb1:
                return _return;
            case 0xbc:
                return new NEW_ARRAY();
            case 0xbd:
                return new ANEW_ARRAY();
            case 0xbe:
                return arraylength;
            case 0xc5:
                return new MULTI_ANEW_ARRAY();
            case 0x2e:
                return iaload;
            case 0x2f:
                return laload;
            case 0x30:
                return faload;
            case 0x31:
                return daload;
            case 0x32:
                return aaload;
            case 0x33:
                return baload;
            case 0x34:
                return caload;
            case 0x35:
                return saload;
            case 0x4f:
                return iastore;
            case 0x50:
                return lastore;
            case 0x51:
                return fastore;
            case 0x52:
                return dastore;
            case 0x53:
                return aastore;
            case 0x54:
                return bastore;
            case 0x55:
                return castore;
            case 0x56:
                return sastore;
            case 0xfe:
                return invoke_native;
            case 0xbf:
                return athrow;
            case 0xc2:
                return monitorenter;
            case 0xc3:
                return monitorexit;
            default:
                throw new RuntimeException("未找到指定指令");
        }
    }
}
